package com.bullsora.kindlerss.model;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.ScriptAssert;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;

import javax.persistence.*;
import javax.validation.groups.Default;
import java.util.HashSet;
import java.util.Set;

@RooJavaBean
@RooToString
@ScriptAssert(lang = "javascript", script = "'' + _this.inputPassword == '' + _this.inputRePassword", message = "{AppUser.error.re_password_must_match_password}", groups = {com.bullsora.kindlerss.model.AppUser.PasswordInput.class})
@Table(name = "appuser")
@RooJpaActiveRecord(finders = {"findAppUsersByEmailEquals"})
public class AppUser {

  private static ThreadLocal<AppUser> currentUserHolder = new ThreadLocal<AppUser>();

  public static AppUser getCurrentUser() {
    return currentUserHolder.get();
  }

  public static void setCurrentUser(AppUser currentUser) {
    currentUserHolder.set(currentUser);
  }

  public static void clearCurrentUser() {
    currentUserHolder.remove();
  }

  @NotBlank
  private String kindleAccount;

  @NotBlank
  private String timezone;

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  private Set<Subscription> subscriptions = new HashSet<Subscription>();

  @Column(unique = true)
  @Email
  @NotBlank
  private String email;

  private String password;

  @Transient
  @NotBlank(groups = {com.bullsora.kindlerss.model.AppUser.PasswordInput.class})
  private String inputPassword;

  @Transient
  @NotBlank(groups = {com.bullsora.kindlerss.model.AppUser.PasswordInput.class})
  private String inputRePassword;

  public interface PasswordInput extends Default {
  }

  public static <T> TypedQuery<T> getAppUserDependentQuery(String baseQuery, String namedInstance, Class<T> clazz) {
    TypedQuery<T> query;
    if (AppUser.getCurrentUser() != null) {
      if (!baseQuery.contains("where")) {
        baseQuery += " where ";
      } else {
        baseQuery += " and ";
      }

      query = entityManager()
          .createQuery(baseQuery + namedInstance + ".appUser = :user", clazz)
          .setParameter("user", AppUser.getCurrentUser());
    } else {
      query = entityManager().createQuery(baseQuery, clazz);
    }
    return query;
  }

  public interface AppUserOwnedEntity {

    public AppUser getAppUser();

    public void setAppUser(AppUser appUser);
  }

  public static class AppUserOwnedEntityListener {

    @PrePersist
    @PreUpdate
    public void setOwningUser(Object entity) {
      if (!(entity instanceof AppUserOwnedEntity) || AppUser.getCurrentUser() == null) {
        return;
      }

      ((AppUserOwnedEntity) entity).setAppUser(AppUser.getCurrentUser());
    }
  }
}
